﻿<%@ WebHandler Language="C#" Class="MetaJogger" %>

using System;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Xml;
using System.Xml.XPath;
using CookComputing.XmlRpc;
using jabber;
using jabber.client;
using System.Security.Cryptography.X509Certificates;
using System.Net.Security;

public class MetaJogger : XmlRpcService, IMetaJogger  
{
    public MetaJogger()
    {
        //ignore invalid security certificates
        bedrock.net.AsyncSocket.UntrustedRootOK = true;
        ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CertificateValid);
    }
    
    public string BlogUrl
    {
        get
        {
            return Context.Request.QueryString["BlogUrl"];
        }
    }

    public string BlogId
    {
        get
        {
            if (Context.Request.QueryString["BlogId"]!=string.Empty)
                return Context.Request.QueryString["BlogId"];
            
            int pos = BlogUrl.IndexOf(".jogger.pl");
            if (pos != -1)
            {
                return Regex.Replace(BlogUrl.Substring(0, BlogUrl.Length - pos), @"^(http://)?(www.)?", string.Empty);
            }
            throw new ArgumentException("Nie podano JID"); 
        }
    }
    
    static ManualResetEvent wait;


    public static bool CertificateValid(Object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
    {
        return true;
    }
    JabberClient Authenticate(string username, string password)
    {        
        JabberClient j = new JabberClient();
        JID jid = new JID(username);
        j.User = jid.User;
        j.Password = password;
        j.Server = jid.Server;

        j.AutoRoster = false;
        j.AutoReconnect = -1;
        
        j.OnError += new bedrock.ExceptionHandler(j_OnError);
        j.OnAuthenticate += new bedrock.ObjectHandler(j_OnAuthenticate);

        wait = new ManualResetEvent(false);
        
        j.Connect();
        wait.WaitOne(10000, false);
        
        return j;
    }

    void j_OnAuthenticate(object sender)
    {
        wait.Set();
    }

    void j_OnError(object sender, Exception ex)
    {
        throw ex;
    }

    private string GetRssUrl(int numberOfPosts)
    {
        return string.Format("{0}/rss/content/html/{1}/", BlogUrl, numberOfPosts);
    }

    public XmlRpcStruct[] getUsersBlogs(string appKey, string username, string password)
    {
        XmlRpcStruct rpcstruct = new XmlRpcStruct();
        rpcstruct.Add("blogid", BlogId); // Blog Id
        rpcstruct.Add("blogName", BlogId); // Blog Name
        rpcstruct.Add("url", BlogUrl); // Blog URL
        XmlRpcStruct[] datarpcstruct = new XmlRpcStruct[] { rpcstruct };
        return datarpcstruct;
    }

    public XmlRpcStruct[] getRecentPosts(string blogid, string username, string password, int numberOfPosts)
    {
        XPathDocument xdoc = new XPathDocument(GetRssUrl(numberOfPosts));
        XPathNavigator nav = xdoc.CreateNavigator();
        XPathNodeIterator iterator = nav.Select("rss/channel/item[position()<=" + numberOfPosts + "]");
        XmlRpcStruct[] posts = new XmlRpcStruct[iterator.Count];
        int i = 0;

        //Populate structure with post entities
        while (iterator.MoveNext() && i < numberOfPosts)
        {
            XmlRpcStruct rpcstruct = new XmlRpcStruct();
            rpcstruct.Add("title", iterator.Current.SelectSingleNode("title").Value);
            rpcstruct.Add("link", iterator.Current.SelectSingleNode("link").Value);
            rpcstruct.Add("description", iterator.Current.SelectSingleNode("description").Value);
            rpcstruct.Add("pubDate", iterator.Current.SelectSingleNode("pubDate").Value);
            rpcstruct.Add("dateCreated", iterator.Current.SelectSingleNode("pubDate").Value);
            rpcstruct.Add("guid", iterator.Current.SelectSingleNode("guid").Value);
            rpcstruct.Add("postid", iterator.Current.SelectSingleNode("guid").Value);
            rpcstruct.Add("userid", username);
            rpcstruct.Add("author", username);

            XPathNodeIterator cat = iterator.Current.Select("category");
            XmlRpcStruct[] categories = new XmlRpcStruct[cat.Count];

            int j = 0;
            while (cat.MoveNext())
            {
                categories[j] = new XmlRpcStruct();
                categories[j].Add("description", cat.Current.Value);
                categories[j].Add("categoryid", cat.Current.Value);
                categories[j].Add("title", cat.Current.Value);
                j++;
            }
            rpcstruct.Add("category", categories);
            posts[i] = rpcstruct;
            i++;
        }
        return posts;
    }

    public XmlRpcStruct getPost(string postid, string username, string password)
    {
        XmlDocument doc = new XmlDocument();
        doc.Load(GetRssUrl(50));
        XmlNode node = doc.SelectSingleNode(string.Format("rss/channel/item/guid[text() ='{0}']/..", postid));

        XmlRpcStruct rpcstruct = new XmlRpcStruct();
        rpcstruct.Add("title", node.SelectSingleNode("title").InnerText);
        rpcstruct.Add("link", node.SelectSingleNode("link").InnerText);
        rpcstruct.Add("description", node.SelectSingleNode("description").InnerText);
        rpcstruct.Add("pubDate", node.SelectSingleNode("pubDate").InnerText);
        rpcstruct.Add("dateCreated", node.SelectSingleNode("pubDate").InnerText);
        rpcstruct.Add("guid", node.SelectSingleNode("guid").InnerText);
        rpcstruct.Add("postid", node.SelectSingleNode("guid").InnerText);
        rpcstruct.Add("userid", username);
        rpcstruct.Add("author", username);

        XmlNodeList cat = node.SelectNodes("category");
        if (cat != null)
        {
            XmlRpcStruct[] categories = new XmlRpcStruct[cat.Count];

            for (int i = 0; i < cat.Count; i++)
            {
                categories[i] = new XmlRpcStruct();
                categories[i].Add("description", cat[i].InnerText);
                categories[i].Add("categoryid", cat[i].InnerText);
                categories[i].Add("title", cat[i].InnerText);
            }
            rpcstruct.Add("category", categories);
        }

        return rpcstruct;
    }

    private static string newId;
    public string newPost(string blogid, string username, string password, XmlRpcStruct rpcstruct, bool publish)
    {
        JabberClient j = Authenticate(username, password);
        j.OnMessage += new MessageHandler(j_OnMessage);
        StringBuilder sb = new StringBuilder(string.Format("(tytul:{0})\n", rpcstruct["title"]));

        if (rpcstruct["categories"] != null && rpcstruct["categories"].ToString().Trim() != String.Empty)
        {
            string[] table = rpcstruct["categories"] as string[];
            if (table!=null && table.Length>0)
                sb.AppendLine(string.Format("(kategoria:{0})", string.Join(",", table)));
            else
                sb.AppendLine(string.Format("(kategoria:{0})", rpcstruct["categories"]));
        }
            

        if (!publish)
            sb.AppendLine("(draft:1)");

        if (rpcstruct["description"] != null && rpcstruct["description"].ToString().Trim() != String.Empty)
            sb.Append(rpcstruct["description"].ToString());

        j.Message(blogid + "@jogger.pl", sb.ToString());
        
        wait = new ManualResetEvent(false);
        wait.WaitOne(10000, false);
        
        return newId;
    }

    void j_OnMessage(object sender, jabber.protocol.client.Message msg)
    {
        newId = Regex.Match(msg.InnerText, @"http://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?").Value;
        JabberClient j = (sender as JabberClient);
        j.Close();
        wait.Set();
    }

    public XmlRpcStruct[] getCategories(string blogid, string username, string password)
    {
        WebClient client = new WebClient();
        client.Encoding = Encoding.UTF8;
        string page = client.DownloadString(BlogUrl);
        MatchCollection matches = Regex.Matches(page, @"(?<url>(http\://[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}/kategoria/(?<title>[a-zA-Z0-9\-\//.]{1,})/))" + "\"" + @"?.{1,}\>(?<desc>.{1,})\</a>");
        XmlRpcStruct[] structs = new XmlRpcStruct[matches.Count];
        int i = 0;
        foreach (Match m in matches)
        {
            structs[i] = new XmlRpcStruct();
            structs[i].Add("title", m.Groups["desc"].Value);
            structs[i].Add("categoryid", m.Groups["title"].Value);
            structs[i].Add("description", m.Groups["desc"].Value);
            structs[i].Add("htmlUrl", m.Groups["url"].Value);
            structs[i].Add("rssUrl", m.Groups["url"].Value.Replace("/kategoria/", "/rss/cat/"));

            i++;
        }
        return structs;
    }
    
    public XmlRpcStruct getUserInfo(string key, string username, string password)
    {
        XmlRpcStruct info = new XmlRpcStruct();
        info.Add("userid", BlogId);
        info.Add("username", username);
        info.Add("lastname", username.Split('@')[1]);
        info.Add("firstname", username.Split('@')[0]);
        info.Add("email", username);
        info.Add("url", BlogUrl);
        return info;
    }

    public bool deletePost(string appKey, string postid, string username, string password, bool publish)
    {
        throw new NotImplementedException("Usuwanie postów nie zostało zaimplementowane");
    }

    public XmlRpcStruct newMediaObject(string blogid, string username, string password, XmlRpcStruct rpcstruct)
    {
        throw new NotImplementedException("Funkcja newMediaObject nie została zaimplementowana");
    }

    public bool editPost(string postid, string username, string password, XmlRpcStruct rpcstruct, bool publish)
    {
        throw new NotImplementedException("Edycja postów nie została zaimplementowana");
    }
}